home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / Menu.C < prev    next >
C/C++ Source or Header  |  1992-07-16  |  13KB  |  640 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.   
  5. #include "Menu.h"
  6.  
  7. #include "Class.h"
  8. #include "OrdColl.h"
  9. #include "String.h"
  10. #include "Window.h"
  11. #include "CollView.h"
  12. #include "TextItem.h"
  13. #include "Look.h"
  14. #include "Box.h"
  15.  
  16. static int menulevel;
  17.  
  18. //---- MenuButtonItem ----------------------------------------------------------
  19.  
  20. NewMetaImpl0(MenuButtonItem, StateButton);
  21.  
  22. MenuButtonItem::MenuButtonItem(int id, char *l, char *s) : StateButton(id, state)
  23. {
  24.     SetLabel(l);
  25.     SetShortCut(s);
  26.     SetFlag(eVObjVFixed|eVObjHFixed);
  27. }
  28.  
  29. MenuButtonItem::MenuButtonItem(int id, VObject *l, char *s) : StateButton(id, state)
  30. {
  31.     Add(l);
  32.     SetShortCut(s);
  33.     SetFlag(eVObjVFixed|eVObjHFixed);
  34. }
  35.  
  36. Metric MenuButtonItem::GetMinSize()
  37. {
  38.     return gLook->MenuItemLayout()->GetMinSize(this);
  39. }
  40.  
  41. void MenuButtonItem::SetOrigin(Point at)
  42. {
  43.     VObject::SetOrigin(at);
  44.     gLook->MenuItemLayout()->SetOrigin(this, at);
  45. }
  46.  
  47. void MenuButtonItem::SetExtent(Point e)
  48. {
  49.     CompositeVObject::SetExtent(e);
  50. }
  51.  
  52. void MenuButtonItem::DrawInner(Rectangle, bool highlight)
  53. {
  54.     int code= state;
  55.     if (state > 0)
  56.     SETBIT(code, 2);
  57.     if (highlight)
  58.     SETBIT(code, 3);
  59.     if (Enabled())
  60.     SETBIT(code, 5);
  61.     gLook->MenuItemLayout()->Adorn(this, contentRect, code);
  62. }
  63.  
  64. char *MenuButtonItem::AsString()
  65. {
  66.     return At(0)->AsString();
  67. }
  68.  
  69. void MenuButtonItem::SetShortCut(char *sc)
  70. {
  71.     if (sc) {
  72.     char *s= form("\327%c", sc[0]);
  73.     if (Size() > 1) {
  74.         TextItem *t= (TextItem*) At(1);
  75.         t->SetString(s);
  76.     } else
  77.         Add(new TextItem(s));
  78.     }
  79. }
  80.  
  81. void MenuButtonItem::SetLabel(char *s)
  82. {
  83.     if (s) {
  84.     if (Size() > 0) {
  85.         TextItem *t= (TextItem*) At(0);
  86.         t->SetString(s);
  87.     } else
  88.         Add(new TextItem(s));
  89.     }
  90. }
  91.  
  92. void MenuButtonItem::SetString(char *s)
  93. {
  94.     char *cp, buf1[100];
  95.     int i;
  96.  
  97.     for (i= 0, cp= s; *cp && *cp != '@'; cp++, i++)
  98.     buf1[i]= *cp;
  99.  
  100.     if (*cp == '@') {
  101.     buf1[i]= 0;
  102.     SetLabel(buf1);
  103.     SetShortCut(&cp[1]);
  104.     } else {
  105.     SetLabel(s);
  106.     SetShortCut(0);
  107.     }
  108. }
  109.  
  110. void MenuButtonItem::InputKbd(Token &t)
  111. {
  112.     if (Enabled() && Size() > 1) {
  113.     TextItem *ti= (TextItem*) At(1);
  114.     char *s= ti->AsString();
  115.     if (s && upcase[s[1]] == upcase[t.Code & 0x7f])
  116.         Control(GetId(), cPartToggle, (void*) 1);
  117.     }
  118. }
  119.  
  120. int MenuButtonItem::Compare(Object *op)
  121. {
  122.     return strcmp(AsString(), op->AsString());
  123. }
  124.  
  125. //---- MouseTracker ------------------------------------------------------------
  126.  
  127. class MouseTracker: public Command {
  128.     VObject *last, *vop;
  129.     Menu *menu;
  130.     Rectangle exitRect;
  131. public:
  132.     MouseTracker(Menu *m, VObject *v, Rectangle er)
  133.     { menu= m; exitRect= er; vop= v; }
  134.     void TrackFeedback(Point, Point, bool)
  135.     { }
  136.     Command *TrackMouse(TrackPhase, Point, Point, Point);
  137. };
  138.  
  139. Command *MouseTracker::TrackMouse(TrackPhase atp, Point, Point, Point np)
  140. {
  141.     Point pp= vop->GetPortPoint(np);
  142.     if (pp.y < 0 && exitRect.IsNotEmpty() && !exitRect.ContainsPoint(pp))
  143.        return gNoChanges;
  144.     if (menulevel > 1 && (pp.x < 0 || pp.y < 0))
  145.        return gNoChanges;
  146.     
  147.     VObject *itemptr= menu->FindAnItem(np);
  148.     
  149.     switch (atp) {
  150.     case eTrackPress:
  151.     if (itemptr)
  152.         itemptr->DoTrackMouse(eTrackPress, np);
  153.     break;
  154.     case eTrackMove:
  155.     if (itemptr != last) {
  156.         if (last)
  157.         last->DoTrackMouse(eTrackExit, np);
  158.         if (itemptr)
  159.         itemptr->DoTrackMouse(eTrackPress, np);
  160.         last= itemptr;
  161.     } else if (itemptr)
  162.         itemptr->DoTrackMouse(eTrackMove, np);
  163.     break;
  164.     case eTrackExit:
  165.     case eTrackRelease:
  166.     if (itemptr)
  167.         itemptr->DoTrackMouse(atp, np);
  168.     return gNoChanges;
  169.     case eTrackIdle:
  170.     break;
  171.     }
  172.     return this;
  173. }
  174.  
  175. //---- Menu --------------------------------------------------------------------
  176.  
  177. NewMetaImpl(Menu,Manager, (TP(view), T(selection), TP(clipper), T(resetAll),
  178.                                     T(dimAll)));
  179.  
  180. Menu::Menu(char *t, bool da, bool ra, int r, int c, SeqCollection *col) : Manager(t)
  181. {
  182.     Init(cIdNone, t, da, ra, r, c, col);
  183. }
  184.  
  185. Menu::Menu(int id, char *t, bool da, bool ra, int r, int c, SeqCollection *col) : Manager(t)
  186. {
  187.     Init(id, t, da, ra, r, c, col);
  188. }
  189.  
  190. Menu::~Menu()
  191. {
  192.     SafeDelete(view);
  193. }
  194.  
  195. void Menu::Init(int id, char*, bool da, bool ra, int r, int c, SeqCollection *col)
  196. {
  197.     if (1) {
  198.     if (col == 0)
  199.         col= new OrdCollection;
  200.     view= new CollectionView(this, col, eCVDontStuckToBorder, r, c);
  201.     } else
  202.     view= new Box(cIdNone, Point(c,r), gPoint0, eVObjHExpand, col);
  203.     view->ResetFlag(eVObjKbdFocus);
  204.     selection= cIdNone;
  205.     resetAll= ra;
  206.     dimAll= da;
  207.     SetId(id);
  208.     nextHandler= 0;
  209. }
  210.  
  211. void Menu::SetNextHandler(EvtHandler *eh)
  212. {
  213.     nextHandler= eh;
  214. }
  215.  
  216. EvtHandler *Menu::GetNextHandler()
  217. {
  218.     if (nextHandler)
  219.     return nextHandler;
  220.     return gFirstHandler;
  221. }
  222.  
  223. VObject *Menu::FindAnItem(Point p)
  224. {
  225.     Iter next(GetCollection());
  226.     register VObject *vop;
  227.     
  228.      while (vop= (VObject*) next())
  229.     if (vop->ContainsPoint(p))
  230.         return vop;
  231.     return 0;
  232. }
  233.  
  234. VObject *Menu::FindInitialItem(int id)
  235. {
  236.     VObject *vop= 0;
  237.     if (id != cIdNone)
  238.     if (vop= FindItem(id))
  239.         return vop;
  240.     return (VObject*) GetCollection()->First();
  241. }
  242.  
  243. Point Menu::GetInitialPos(Point)
  244. {
  245.     return gPoint0;
  246. }
  247.  
  248. void Menu::SetSelectedItem(int id)
  249. {
  250.     selection= id;
  251. }
  252.  
  253. Window *Menu::DoMakeWindows()
  254. {
  255.     return
  256.     new Window(this,
  257.         clipper= new Clipper(view, cAutoSize, cIdNone, gInkNone),
  258.         eWinPulldownMenu,
  259.         eWinDefault,
  260.         cAutoSize,
  261.         GetName()
  262.     );
  263. }
  264.  
  265. int Menu::CheckKey(Token &t)
  266. {
  267.     if (view && view->IsKindOf(CollectionView))
  268.     ((CollectionView*)view)->Update();
  269.     
  270.     if (resetAll)
  271.     ResetAll();
  272.     if (dimAll) 
  273.     DisableAll();
  274.     if (GetNextHandler())
  275.     GetNextHandler()->DoSetupMenu(this);
  276.  
  277.     if (GetCollection()->Size() <= 0)
  278.     return cIdNone;
  279.  
  280.     Iter next(GetCollection());
  281.     register VObject *vop;
  282.  
  283.     int oldselection= selection;
  284.     selection= cIdNone;
  285.  
  286.     while (vop= (VObject*) next())
  287.     if (vop->IsKindOf(MenuButtonItem)) {
  288.         ((MenuButtonItem*)vop)->InputKbd(t);
  289.         if (selection != cIdNone)
  290.         break;
  291.     }
  292.  
  293.     if (selection == cIdNone) {
  294.     selection= oldselection;
  295.     return cIdNone;
  296.     }
  297.     return selection;
  298. }
  299.  
  300. extern Point showdelta;
  301.  
  302. int Menu::Popup(Point p, VObject *fp, int id, bool showlast,
  303.                         int menupos, Rectangle exitr)
  304. {
  305.     if (resetAll)
  306.     ResetAll();
  307.     if (dimAll) 
  308.     DisableAll();
  309.     
  310.     if (GetNextHandler())
  311.     GetNextHandler()->DoSetupMenu(this);
  312.     
  313.     if (GetCollection()->Size() <= 0)
  314.     return cIdNone;
  315.  
  316.     selection= id;
  317.  
  318.     MakeWindows();
  319.     
  320.     if (TestFlag(eMenuNoScroll)) {
  321.     clipper->SetMinExtent(cAutoSize);
  322.     } else {
  323.     Point e= view->GetMinSize().extent;
  324.     if (view->IsKindOf(CollectionView)) {
  325.         Rectangle r(((CollectionView*)view)->ItemRect(2,20));
  326.         clipper->SetMinExtent(r.origin+r.extent);
  327.     } else
  328.         clipper->SetMinExtent(Min(Point(200), e));
  329.     clipper->Scroll(cPartScrollAbs, gPoint0, FALSE);
  330.     }
  331.  
  332.     if (view->IsKindOf(View))
  333.     ((View*)view)->ClearSelection(FALSE);
  334.     
  335.     Point lp;
  336.     GetWindow()->GetMinSize();
  337.     VObject *vop= FindInitialItem(selection);
  338.     if (vop) {
  339.     if (menupos)
  340.         lp= vop->contentRect.origin;
  341.     else
  342.         lp= vop->contentRect.W()+Point(4,0);
  343.     }
  344.     
  345.     int oldselection= selection;
  346.     selection= cIdNone;
  347.     
  348.     Point pp= view->GetPortPoint(lp);
  349.     if (pp == gPoint0) {    // this is a hack
  350.     pp= gPoint2;
  351.     }   
  352.  
  353.     OpenAt(fp, p - pp + Point(2,3), TRUE, FALSE);
  354.     
  355.     menulevel++;
  356.     if (!showlast)
  357.     lp= gPoint_1;
  358.  
  359.     exitr.origin-= showdelta;
  360.     view->TrackInContent(lp, Token(), new MouseTracker(this, view, exitr));
  361.     menulevel--;
  362.     Close();
  363.     
  364.     if (selection == cIdNone) {
  365.     selection= oldselection;
  366.     return cIdNone;
  367.     }
  368.     return selection;
  369. }
  370.  
  371. int Menu::Pulldown(Point p, VObject *vop)
  372. {
  373.     return Popup(p, vop, selection, TRUE, FALSE, gRect0);
  374. }
  375.  
  376. void Menu::Control(int id, int part, void*)
  377. {
  378.     if (part == cPartToggle)
  379.     selection= id;
  380. }
  381.  
  382. OStream& Menu::PrintOn(OStream &s)
  383. {
  384.     Manager::PrintOn(s);
  385.     return s << view SP << selection SP << resetAll SP << dimAll SP;
  386. }
  387.  
  388. IStream& Menu::ReadFrom(IStream &s)
  389. {
  390.     Manager::ReadFrom(s);
  391.     return s >> view >> selection >> resetAll >> dimAll;
  392. }
  393.  
  394. SeqCollection *Menu::GetCollection()
  395. {
  396.     if (view->IsKindOf(CollectionView))
  397.     return ((CollectionView*)view)->GetCollection();
  398.     if (view->IsKindOf(CompositeVObject))
  399.     return ((CompositeVObject*)view)->GetList();
  400.     return 0;
  401. }
  402.  
  403. void Menu::SetCollection(SeqCollection *c, bool freeold)
  404. {
  405.     if (view->IsKindOf(CollectionView))
  406.     ((CollectionView*)view)->SetCollection(c, freeold);
  407. }
  408.  
  409. void Menu::Insert(VObject *mip)
  410. {
  411.     GetCollection()->AddFirst(mip);
  412. }
  413.  
  414. void Menu::InsertItem(char *s, int id)
  415. {
  416.     Insert(MakeMenuItem(s, id));
  417. }
  418.  
  419. void Menu::Append(VObject *mip)
  420. {
  421.     GetCollection()->Add(mip);
  422. }
  423.  
  424. VObject *Menu::FindItem(int id)
  425. {
  426.     Iter next(GetCollection());
  427.     register VObject *vop;
  428.     
  429.      while (vop= (VObject*) next())
  430.     if (vop->GetId() == id)
  431.         return vop;
  432.     return 0;
  433. }
  434.  
  435. void Menu::InsertBefore(int id, VObject *mip)
  436. {
  437.     VObject *vop= FindItem(id);
  438.  
  439.     if (vop)
  440.     GetCollection()->AddBeforePtr(mip, vop);
  441.     else
  442.     GetCollection()->AddFirst(mip);
  443. }
  444.  
  445. void Menu::InsertAfter(int id, VObject *mip)
  446. {
  447.     VObject *vop= FindItem(id);
  448.  
  449.     if (vop)
  450.     GetCollection()->AddAfterPtr(mip, vop);
  451.     else
  452.     GetCollection()->Add(mip);
  453. }
  454.  
  455. void Menu::InsertItemAfter(int atId, char *s, int id)
  456. {
  457.     InsertAfter(atId, MakeMenuItem(s, id));
  458. }
  459.  
  460. void Menu::InsertItemBefore(int atId, char *s, int id)
  461. {
  462.     InsertBefore(atId, MakeMenuItem(s, id));
  463. }
  464.  
  465. void Menu::AppendItem(char *s, int id)
  466. {
  467.     GetCollection()->Add(MakeMenuItem(s, id));
  468. }
  469.  
  470. void Menu::AppendItems(char *va_(first), ...)
  471. {
  472.     va_list ap;
  473.     va_start(ap,va_(first)); 
  474.     InsertVItems(cIdNone, FALSE, va_(first), ap);
  475.     va_end(ap);
  476. }
  477.  
  478. void Menu::InsertItemsBefore(int va_(atId), ...)
  479. {
  480.     va_list ap;    
  481.     va_start(ap,va_(atId));
  482.     char *first= va_arg(ap, char*);
  483.     InsertVItems(va_(atId), TRUE, first, ap);
  484.     va_end(ap);
  485. }
  486.  
  487. void Menu::InsertItemsAfter(int va_(atId), ...)
  488. {
  489.     va_list ap;    
  490.     va_start(ap,va_(atId));
  491.     char *first= va_arg(ap, char*);
  492.     InsertVItems(va_(atId), FALSE, first, ap);
  493.     va_end(ap);
  494. }
  495.  
  496. VObject *Menu::MakeMenuItem(char *s, int id)
  497. {
  498.     if (strcmp(s, "-") == 0)
  499.     return new Separator;
  500.     MenuButtonItem *mi= new MenuButtonItem(id, "");
  501.     mi->SetString(s);
  502.     return mi;
  503. }
  504.  
  505. void Menu::InsertVItems(int atId, bool before, char *first, va_list ap)
  506. {
  507.     SeqCollection *col= GetCollection();
  508.     int id= cIdNone;
  509.     VObject *vop, *atvop= 0;
  510.  
  511.     if (atId != cIdNone)
  512.     atvop= FindItem(atId);
  513.  
  514.     for (int i= 0;; i++) {
  515.     char *s= (i == 0) ? first : va_arg(ap, char*);
  516.     if (s == 0)
  517.         break;
  518.     if (strcmp(s, "-"))
  519.         id= va_arg(ap, int);
  520.     vop= MakeMenuItem(s, id);
  521.     if (atvop == 0)
  522.         col->Add(vop); 
  523.     else if (before && i== 0)
  524.         col->AddBeforePtr(vop, atvop);
  525.     else
  526.         col->AddAfterPtr(vop, atvop);
  527.     atvop= vop;
  528.     }
  529. }
  530.  
  531. void Menu::EnableAll(bool b)
  532. {
  533.     GetCollection()->ForEach(VObject,Enable)(b, FALSE);
  534. }
  535.  
  536. void Menu::ResetAll()
  537. {
  538.     Iter next(GetCollection());
  539.     Object *op;
  540.     while (op= next()) 
  541.     if (op->IsKindOf(StateButton))
  542.         ((StateButton*)op)->SetValue(0,FALSE);
  543. }
  544.  
  545. void Menu::CheckItem(int id, int state, int type)
  546. {
  547.     int code= 0;
  548.     VObject *vop= FindItem(id);
  549.     if (vop) {
  550.     StateButton *mi= Guard(vop, StateButton);
  551.     if (state)
  552.         mi->SetValue(type, FALSE);
  553.     else
  554.         mi->SetValue(0, FALSE);
  555.     }
  556. }
  557.  
  558. void Menu::ReplaceItem(int id, char *s)
  559. {
  560.     VObject *v= FindItem(id);
  561.  
  562.     if (v) {
  563.     if (v->IsKindOf(TextItem)) {
  564.         TextItem *t= (TextItem*) v;
  565.         t->SetString(s);
  566.     } else if (v->IsKindOf(MenuButtonItem)) {
  567.         MenuButtonItem *mi= (MenuButtonItem*)v;
  568.         mi->SetString(s);
  569.     }
  570.     if (view->IsKindOf(CollectionView))
  571.         ((CollectionView*)view)->Modified();
  572.     }
  573. }
  574.     
  575. void Menu::ToggleItem(int id, bool toggle, char *toggleTrue, char *toggleFalse)
  576. {
  577.     ReplaceItem(id, toggle ? toggleTrue : toggleFalse);
  578. }
  579.  
  580. void Menu::ToggleItem(int id, bool toggle, char *fmt, char *toggleTrue, char *toggleFalse)
  581. {
  582.     ReplaceItem(id, form(fmt, toggle ? toggleTrue : toggleFalse));
  583. }
  584.  
  585. VObject *Menu::RemoveItem(int id)
  586. {
  587.     VObject *vop= FindItem(id);
  588.     if (vop) {
  589.     VObject *cont= vop->GetContainer();
  590.     Menu *m= this;
  591.     if (cont && cont->IsKindOf(Menu))
  592.         m= (Menu*)cont;    
  593.     m->GetCollection()->RemovePtr(vop);
  594.     }
  595.     return vop;
  596. }
  597.  
  598. void Menu::RemoveAllItems(bool free)
  599. {
  600.     // view->ClearSelection();
  601.     Collection *cp= GetCollection();
  602.     if (free)
  603.     cp->FreeAll();
  604.     cp->RemoveAll(cp);
  605. }
  606.  
  607. Menu *Menu::FindMenuItem(int id)
  608. {
  609.     VObject *vop= FindItem(id);
  610.     if (!vop || !vop->IsKindOf(MenuItem))
  611.     return 0;
  612.     MenuItem *mip= (MenuItem*)vop;
  613.     return mip->MyMenu();
  614. }
  615.  
  616. void Menu::EnableItem(int id, bool b)
  617. {
  618.     VObject *vop= FindItem(id);
  619.     if (vop)
  620.     vop->Enable(b, FALSE);
  621. }
  622.  
  623. void Menu::EnableItems(int va_(first), ...)
  624. {
  625.     va_list ap;
  626.     va_start(ap,va_(first));
  627.     register int id;
  628.     
  629.     EnableItem(va_(first));
  630.     while (id= va_arg(ap, int))
  631.     EnableItem(id);
  632.     va_end(ap);
  633. }
  634.  
  635. void Menu::AppendMenu(Menu *m, int id)
  636. {
  637.     Append(new MenuItem(id, new TextItem(m->GetName()), m));
  638. }
  639.  
  640.